Loading the necessary libraries and packages

library(pacman)
pacman::p_load(data.table, ggplot2, lubridate, stringr, ggpubr, dplyr, cowplot, readxl, scales, knitr)

Input_Directory <- "./ALL_PLATES/"
save_to         <- Input_Directory
# adjust the names as needed!
NAME_KEY <- fread("./ELISA_CL_KEY.csv", header = T) 
# head(NAME_KEY, n = 10)
source(file = ifelse(exists("https://raw.githubusercontent.com/tlobnow/coding_universe/main/scripts/ELISA_Fx.R"), 
                     yes =  "https://raw.githubusercontent.com/tlobnow/coding_universe/main/scripts/ELISA_Fx.R",
                     no  =  "./scripts/ELISA_Fx.R"))

From raw measurements to estimated sample concentrations

  1. Calculate the mean values per Standard Curve dilution step
  2. Plot the Standard curve and fit a linear trend line
  3. Save the plots

We use the equation to estimate IL-2 conc. of our unknown samples

Running ELISA_Fx() to generate standard curves and calculate the IL-2 concentrations.

## [1] "Plates exist!"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 352.419126169057*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 320.070381583682*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 306.346853473382*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 358.251952014523*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 298.804571083167*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 347.167928535214*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 559.423714931026*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 58.1684699766724*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 205.43426617438*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 1080.06019989381*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 1076.81100367551*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 659.569606790955*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 1015.10890429452*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 1076.81100367551*Intensity"
## [1] "Secretion = slope*Intensity"
## [1] "Secretion = 590.8221002662*Intensity"

Amyoids ELISA Results 2024-01-31

FILTER_VALUES = as.IDate("2024-01-31")
FILTER_VALUE = as.IDate("2024-01-31")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
save = T

x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
DF = All_plates_data
SEED = 1
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # extra filter
  COHORT_DATA <- COHORT_DATA %>%
  filter((Plate == 1 & STIM_CONCENTRATION == 5) | 
         (Plate == 2 & CELL_LINE == "cl204" & STIM_CONCENTRATION == 5) | 
         !(Plate == 2 & CELL_LINE == "cl204" & STIM_CONCENTRATION == 5 & MEASUREMENT > 1))
  
  COHORT_DATA <- COHORT_DATA %>%
    filter(STIM_CONCENTRATION == 5) %>%
    filter(!(CELL_LINE == "cl204" & MEASUREMENT > 1)) %>%
    filter(Plate != 3)
  
  # Prepare Normalization
  group_vars <- c("Date", "STIM_DAY")
  
  baseline <- COHORT_DATA %>%
      group_by(!!!syms(group_vars)) %>%
      filter((CELL_LINE %in% NEGATIVE_CTRL & CONDITION == "UNSTIM") | (CL_NAME_ON_PLOT %in% NEGATIVE_CTRL & CONDITION == "UNSTIM")) %>%
      summarise(baseline_control_value = mean(Concentration))
  
   # Join the calculated values with the dataset
  data <- left_join(COHORT_DATA, baseline, by = group_vars) %>%
      mutate(Concentration_REDUCED = case_when(!is.na(baseline_control_value) ~ Concentration - baseline_control_value, TRUE ~ Concentration))
  
  control_mean_per_day <- data %>%
      filter((CELL_LINE %in% POSITIVE_CTRL & CONDITION == "STIM") | (CL_NAME_ON_PLOT %in% POSITIVE_CTRL & CONDITION == "STIM")) %>%
      group_by(!!!syms(group_vars)) %>%
      summarise(control_mean_MEASUREMENT = case_when(mean(Concentration_REDUCED) > 0 ~ mean(Concentration_REDUCED), TRUE ~ -Inf))
    
    # Join the calculated control means
    data <- left_join(data, control_mean_per_day, by = group_vars)
    
    # Perform normalization
    DATA_NORMALIZED <- data %>%
      group_by(!!!syms(group_vars), CELL_LINE, CONDITION) %>%
      mutate(Concentration_NORMALIZED = case_when(Concentration_REDUCED / control_mean_MEASUREMENT < 0 ~ 0, TRUE ~ Concentration_REDUCED / control_mean_MEASUREMENT),
             triplicate_mean_per_day  = mean(Concentration_NORMALIZED)) %>%
      ungroup()
  NORMALIZED_DATA <- DATA_NORMALIZED
  return(NORMALIZED_DATA)
})

# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))

# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_1_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}
FILTER_VALUES = as.IDate("2024-01-31")
FILTER_VALUE = as.IDate("2024-01-31")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
save = T

x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
DF = All_plates_data
SEED = 1
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # extra filter
  COHORT_DATA <- COHORT_DATA %>%
    filter(STIM_CONCENTRATION == 100) %>%
    filter(!(Plate == 2 & CELL_LINE == "cl204" & STIM_CONCENTRATION == 100 & MEASUREMENT > 1))

  # Prepare Normalization
  group_vars <- c("Date", "STIM_DAY")
  
  baseline <- COHORT_DATA %>%
      group_by(!!!syms(group_vars)) %>%
      filter((CELL_LINE %in% NEGATIVE_CTRL & CONDITION == "UNSTIM") | (CL_NAME_ON_PLOT %in% NEGATIVE_CTRL & CONDITION == "UNSTIM")) %>%
      summarise(baseline_control_value = mean(Concentration))
  
   # Join the calculated values with the dataset
  data <- left_join(COHORT_DATA, baseline, by = group_vars) %>%
      mutate(Concentration_REDUCED = case_when(!is.na(baseline_control_value) ~ Concentration - baseline_control_value, TRUE ~ Concentration))
  
  control_mean_per_day <- data %>%
      filter((CELL_LINE %in% POSITIVE_CTRL & CONDITION == "STIM") | (CL_NAME_ON_PLOT %in% POSITIVE_CTRL & CONDITION == "STIM")) %>%
      group_by(!!!syms(group_vars)) %>%
      summarise(control_mean_MEASUREMENT = case_when(mean(Concentration_REDUCED) > 0 ~ mean(Concentration_REDUCED), TRUE ~ -Inf))
    
    # Join the calculated control means
    data <- left_join(data, control_mean_per_day, by = group_vars)
    
    # Perform normalization
    DATA_NORMALIZED <- data %>%
      group_by(!!!syms(group_vars), CELL_LINE, CONDITION) %>%
      mutate(Concentration_NORMALIZED = case_when(Concentration_REDUCED / control_mean_MEASUREMENT < 0 ~ 0, TRUE ~ Concentration_REDUCED / control_mean_MEASUREMENT),
             triplicate_mean_per_day  = mean(Concentration_NORMALIZED)) %>%
      ungroup()
  NORMALIZED_DATA <- DATA_NORMALIZED
  return(NORMALIZED_DATA)
})

# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))

# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_2_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}
FILTER_VALUES = as.IDate("2024-01-31")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save = T


SEED = 1
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # extra filter
  COHORT_DATA <- COHORT_DATA %>% filter(Plate == 3)
  
  # Step 2 and Step 3
  NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  return(NORMALIZED_DATA)
})

# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)


# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))

# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_3_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}

Amyoids ELISA Results 2024-02-08

FILTER_VALUES = as.IDate("2024-02-08")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save = T


SEED = 1
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # extra filter
  COHORT_DATA <- COHORT_DATA %>% filter(Plate == 1)
  
  # Step 2 and Step 3
  NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  return(NORMALIZED_DATA)
})

# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))

# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, subtitle = paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_1_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}
FILTER_VALUES = as.IDate("2024-02-08")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save = T


SEED = 600
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # extra filter
  COHORT_DATA <- COHORT_DATA %>% filter(Plate == 2)
  
  # Step 2 and Step 3
  NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  return(NORMALIZED_DATA)
})

# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))

# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, subtitle = paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_2_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}

Amyoids ELISA Results 2024-02-12

FILTER_VALUES = as.IDate("2024-02-12")
FILTER_TYPE   = "DATE"
POSITIVE_CTRL = c("WT_EL4", "cl069")
NEGATIVE_CTRL = c("204_TRIPLE_KO", "tKO_EL4")
x_label = ""
y_label = "relative IL-2 conc."
plot_title = "IL-2 ELISA"
subtitle = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save = T


SEED = 600
plot_pval = T
plot_faceted_by_date = F
formatted_date <- format(as.IDate(FILTER_VALUES), "%Y%m%d")

# processing ELISA
ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
  # Step 1: Filter & Subset the main data into lists
  COHORT_DATA <- filter_data(DF, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  
  # Step 2 and Step 3
  NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
  return(NORMALIZED_DATA)
})
## `summarise()` has grouped output by 'Date', 'STIM_DAY'. You can override using
## the `.groups` argument.
## `summarise()` has grouped output by 'Date', 'STIM_DAY'. You can override using
## the `.groups` argument.
# Step 4: Combine the subset lists into one data frame
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
  group_by(CELL_LINE, CONDITION, Date, PLOTTING_COLOR) %>%
  distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
  ungroup()

# Create a data frame with unique CL_NAME_ON_PLOT and corresponding PLOTTING_COLOR
color_mapping <- unique(MEANS[, c("CL_NAME_ON_PLOT", "PLOTTING_COLOR")])

# Filter rows where CONDITION is "UNSTIM" and set PLOTTING_COLOR to "gray50"
MEANS$PLOTTING_COLOR[MEANS$CONDITION == "UNSTIM"] <- "gray50"
# MEANS$PLOTTING_COLOR[MEANS$CONDITION == "STIM"] <- "#A6529A"

# Merge the MEANS data frame with the color_mapping data frame using dplyr
MEANS_merged <- MEANS %>%
  left_join(color_mapping) %>%
  mutate(CL_NAME_ON_PLOT = factor(CL_NAME_ON_PLOT, levels = unique(MEANS$CL_NAME_ON_PLOT)))
## Joining with `by = join_by(CL_NAME_ON_PLOT, PLOTTING_COLOR)`
# Reorder CL_NAME_ON_PLOT based on ORDER_NO
MEANS_merged$CL_NAME_ON_PLOT <- reorder(MEANS$CL_NAME_ON_PLOT, -MEANS_merged$ORDER_NO)
MEANS_merged$STIM_DAY <- as.factor(MEANS_merged$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS_merged %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, PLOTTING_COLOR, ORDER_NO) %>%
  summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
            triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
  distinct(.keep_all = TRUE)
## `summarise()` has grouped output by 'CELL_LINE', 'CL_NAME_ON_PLOT',
## 'CONDITION', 'Date', 'PLOTTING_COLOR'. You can override using the `.groups`
## argument.
# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS_merged, "CL_NAME_ON_PLOT")

# Your ggplot code
my_plot <- ggplot(MEANS_merged, aes(x = CL_NAME_ON_PLOT)) +
  geom_col(data = MOM_SUBSET,
           aes(y = triplicate_mean_per_day, fill = CONDITION), 
           position = position_dodge(width = 1),
           alpha = 0.5) +
  geom_point(data = MEANS_merged,
             aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "white", size = 4) +
  geom_point(data = MEANS_merged, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
             position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED),
             col = "black", size = 3) +
  geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day,
                                       ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION),
                width = 0.25, position = position_dodge(width = 1)) +
  labs(x = x_label,
       y = y_label) +
  scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = "#A6529A")) +
  ggtitle(plot_title, subtitle = paste0("IL-1ß Concentration ", unique(MEANS_merged$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS_merged$STIM_TIME), "hrs")) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  theme(plot.title = element_text(hjust = 0.5)) +
  coord_flip() +
  facet_wrap(~Date)

my_plot

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("Plate_1_", formatted_date))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(my_plot))
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}

Check Cell Lines Across Assays

# What to adjust:
FILTER_VALUES = "CHARMS-15xTA"
FILTER_VALUE  = "CHARMS-15xTA"
FILTER_TYPE   = "COHORT"
POSITIVE_CTRL = c("cl069")
NEGATIVE_CTRL = c("tKO_EL4", "204_TRIPLE_KO")
COLOR         = "cornflowerblue"
x_label       = ""
y_label       = "relative IL-2 conc."
plot_title    = "IL-2 ELISA"
subtitle      = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save          = T

# Automatic settings
DF = All_plates_data
DF$CL_NAME_ON_PLOT = reorder(DF$CL_NAME_ON_PLOT, -DF$ORDER_NO)
SEED = 600

ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
    # Step 1: Filter & Subset the main data into lists
    COHORT_DATA <- filter_data(All_plates_data, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
    
    COHORT_DATA_CL <- COHORT_DATA %>% filter(CL_NAME_ON_PLOT == FILTER_VALUE) %>% filter(STIM_CONCENTRATION == 5)
    
    # extra filter
    COHORT_DATA <- COHORT_DATA %>%
      filter(STIM_CONCENTRATION == 5) %>%
      filter(Date %in% COHORT_DATA_CL$Date) %>%
      filter(!(Plate == 2 & CL_NAME_ON_PLOT == "tKO_EL4" & MEASUREMENT > 1))
    
    # Step 2 and Step 3
    NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
    return(NORMALIZED_DATA)
})
  
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
    group_by(CELL_LINE, CONDITION, Date) %>%
    distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
    ungroup()

MEANS$STIM_DAY <- as.factor(MEANS$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS %>%
    group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date) %>%
    summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
              triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
    distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS, "CL_NAME_ON_PLOT")

# Step 8: Plot the results
plot_cell_line_summary <- ggplot(MEANS, aes(x = CL_NAME_ON_PLOT)) +
    geom_col(data = MOM_SUBSET, aes(y = triplicate_mean_per_day, fill = CONDITION), 
             position = position_dodge(width = 1), alpha = 0.5) +
    geom_point(data = MEANS, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
               position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED), col = "white", size = 4) +
    geom_point(data = MEANS, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY), 
               position = position_jitterdodge(jitter.height = 0, jitter.width = 1.2, seed = SEED), col = "black", size = 3) +
    geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day, 
                                         ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION), width = 0.25, position = position_dodge(width = 1)) +
    labs(x = x_label, y = y_label) +
  geom_text(data = data.frame(CL_NAME_ON_PLOT = names(STATISTICAL_RESULTS[["annotations"]]), 
                              y = max(MEANS$triplicate_mean_per_day) + 0.1, label = STATISTICAL_RESULTS[["annotations"]]), 
            aes(y = y, label = label), col = "gray40", size = 4) +
  geom_text(data = data.frame(CL_NAME_ON_PLOT = names(STATISTICAL_RESULTS[["p_values"]]), 
                              y = max(MEANS$triplicate_mean_per_day) + 0.2, label = STATISTICAL_RESULTS[["p_values"]]), 
            aes(y = y, label = label), size = 7) +
    scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = COLOR)) +
    ggtitle(plot_title, subtitle = paste0("IL-1ß Concentration ", unique(MEANS$STIM_CONCENTRATION), "ng/mL \n",
                                        "Stimulation Time ", unique(MEANS$STIM_TIME), "hrs")) +
    theme_cowplot() +
    theme(legend.position = "bottom") +
    theme(plot.title = element_text(hjust = 0.5)) +
  facet_wrap(~Date)

plot_cell_line_summary

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("CL_SUMMARY_", FILTER_VALUES, "_", unique(MEANS_merged$STIM_TIME), "hrs_", unique(MEANS_merged$STIM_CONCENTRATION), "ng_mL"))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(plot_cell_line_summary))
  
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}
# What to adjust:
FILTER_VALUES = "CHARMS-15xTA"
FILTER_TYPE   = "COHORT"
POSITIVE_CTRL = c("cl069")
NEGATIVE_CTRL = c("tKO_EL4", "204_TRIPLE_KO")
COLOR         = "cornflowerblue"
x_label       = ""
y_label       = "relative IL-2 conc."
plot_title    = "IL-2 ELISA"
subtitle      = paste0("Assay performed for ", FILTER_VALUES, ", based on filter type ", FILTER_TYPE)
save          = T

# Automatic settings
DF = All_plates_data
DF$CL_NAME_ON_PLOT = reorder(DF$CL_NAME_ON_PLOT, -DF$ORDER_NO)
SEED = 600

ALL_COHORT_DATA <- lapply(FILTER_VALUES, function(FILTER_VALUE) {
    # Step 1: Filter & Subset the main data into lists
    COHORT_DATA <- filter_data(All_plates_data, FILTER_VALUE, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
    
    # extra filter
    COHORT_DATA <- COHORT_DATA %>%
      filter(STIM_CONCENTRATION == 100) %>%
      filter(!(Plate == 2 & CL_NAME_ON_PLOT == "tKO_EL4" & MEASUREMENT > 1))
    
    # Step 2 and Step 3
    NORMALIZED_DATA <- calculate_baseline_and_control(COHORT_DATA, FILTER_TYPE, POSITIVE_CTRL, NEGATIVE_CTRL)
    return(NORMALIZED_DATA)
})
  
COMBINED_DATA <- bind_rows(ALL_COHORT_DATA)

# Step 5: Calculate the means per cohort
MEANS <- COMBINED_DATA %>%
    group_by(CELL_LINE, CONDITION, Date) %>%
    distinct(triplicate_mean_per_day, STIM_DAY, .keep_all = TRUE) %>%
    ungroup()

MEANS$STIM_DAY <- as.factor(MEANS$STIM_DAY)

# Step 6: Calculate the mean of means (MOM) per cohort
MOM_SUBSET <- MEANS %>%
    group_by(CELL_LINE, CL_NAME_ON_PLOT, CONDITION, Date, STIM_TIME, STIM_CONCENTRATION) %>%
    summarise(triplicate_sd_per_day = sd(triplicate_mean_per_day),
              triplicate_mean_per_day = mean(triplicate_mean_per_day)) %>%
    distinct(.keep_all = TRUE)

# Step 7: Perform statistics per cohort
STATISTICAL_RESULTS <- perform_statistical_analysis(MEANS, "CL_NAME_ON_PLOT")

# Step 8: Plot the results
plot_cell_line_summary <- ggplot(MEANS, aes(x = CL_NAME_ON_PLOT)) +
    geom_col(data = MOM_SUBSET, aes(y = triplicate_mean_per_day, fill = CONDITION), 
             position = position_dodge(width = 1), alpha = 0.5) +
    geom_point(data = MEANS, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY),
               position = position_jitterdodge(jitter.height = 0, jitter.width = 1, seed = SEED), col = "white", size = 4) +
    geom_point(data = MEANS, aes(y = triplicate_mean_per_day, group = CONDITION, shape = STIM_DAY), 
               position = position_jitterdodge(jitter.height = 0, jitter.width = 1, seed = SEED), col = "black", size = 3) +
    geom_errorbar(data = MOM_SUBSET, aes(ymin = triplicate_mean_per_day - triplicate_sd_per_day, 
                                         ymax = triplicate_mean_per_day + triplicate_sd_per_day, group = CONDITION), width = 0.25, position = position_dodge(width = 1)) +
    labs(x = x_label, y = y_label) +
  geom_text(data = data.frame(CL_NAME_ON_PLOT = names(STATISTICAL_RESULTS[["annotations"]]), 
                              y = max(MEANS$triplicate_mean_per_day) + 0.1, label = STATISTICAL_RESULTS[["annotations"]]), 
            aes(y = y, label = label), col = "gray40", size = 4) +
  geom_text(data = data.frame(CL_NAME_ON_PLOT = names(STATISTICAL_RESULTS[["p_values"]]), 
                              y = max(MEANS$triplicate_mean_per_day) + 0.2, label = STATISTICAL_RESULTS[["p_values"]]), 
            aes(y = y, label = label), size = 7) +
    scale_fill_manual(values = c("UNSTIM" = "gray50", "STIM" = COLOR)) +
    ggtitle(plot_title, subtitle = paste0("IL-1ß Concentration ", unique(MEANS$STIM_CONCENTRATION), "ng/mL")) +
    theme_cowplot() +
    theme(legend.position = "bottom") +
    theme(plot.title = element_text(hjust = 0.5)) +
  facet_wrap(Date~paste0(STIM_TIME, "hrs"))

plot_cell_line_summary

if (save) {
  # Step 9: Create Output Folder
  folder_path <- file.path(save_to, paste0("CL_SUMMARY_", FILTER_VALUES, "_", 
                                           "24-48hrs_", 
                                           unique(MEANS$STIM_CONCENTRATION), "ng_mL"))
  if (!dir.exists(folder_path)) {dir.create(folder_path, recursive = TRUE)}   # Check if the folder exists, and if not, create it
  
  # Step 10: Save Plots and Data
  save_plots(folder_name = basename(folder_path), plots = list(plot_cell_line_summary))
  
  fwrite(COMBINED_DATA,       file = paste0(folder_path, "/COMBINED_DATA.csv"),       append = F, quote = F, row.names = F, col.names = T)
  fwrite(MEANS,               file = paste0(folder_path, "/MEANS.csv"),               append = F, quote = F, row.names = F, col.names = T)
  fwrite(MOM_SUBSET,          file = paste0(folder_path, "/MOM_SUBSET.csv"),          append = F, quote = F, row.names = F, col.names = T)
  fwrite(STATISTICAL_RESULTS, file = paste0(folder_path, "/STATISTICAL_RESULTS.csv"), append = F, quote = F, row.names = F, col.names = T)
}

Plotting Fold Change

# Step 1: Filter & Subset the main data
COHORT_DATA <- DF %>% filter(Date %in% as.IDate(c("2024-01-31", "2024-02-08", "2024-02-12")))

# Step 2: Set negative values to 1 (NOT ZERO)
COHORT_DATA$MEASUREMENT <- ifelse(COHORT_DATA$MEASUREMENT < 0, yes = 1, COHORT_DATA$MEASUREMENT)

# Normalization for fold change from UNSTIM to STIM
NORMALIZED_TO_CONTROL <- COHORT_DATA %>%
  group_by(Date, STIM_DAY, CELL_LINE, CONDITION, CL_NAME_ON_PLOT) %>%
  summarise(mean_per_day = mean(MEASUREMENT),
            Concentration = mean(Concentration))
      
# First, calculate the mean for the UNSTIM condition separately.
unstim_means <- COHORT_DATA %>%
  filter(CONDITION == "UNSTIM") %>%
  group_by(CELL_LINE) %>%
  summarise(mean_unstim = mean(MEASUREMENT))
      
# Now, join this back to the main dataset.
COHORT_SUBSET <- COHORT_DATA %>%
  left_join(unstim_means, by = "CELL_LINE")
      
# Compute the fold change. 
# The `case_when` logic ensures that the fold change is calculated only for the STIM condition.
NORMALIZED_TO_CONTROL <- COHORT_SUBSET %>%
  mutate(fold_change = case_when(CONDITION == "STIM" ~ MEASUREMENT / mean_unstim, TRUE ~ NA_real_ )) %>% # set NA for non-STIM conditions
  ungroup() %>%
  group_by(CELL_LINE, CONDITION) %>%
  mutate(trip_mean = mean(fold_change),
         fold_change_sd = sd(fold_change)) %>%
  unique()
      
# Helper function to perform a t-test and return p-value and annotation
perform_ttest <- function(data) {
  ttest_result <- t.test(data$MEASUREMENT[data$CONDITION == "STIM"],
                         data$MEASUREMENT[data$CONDITION == "UNSTIM"],
                         paired = TRUE)  # or paired = FALSE if the data are independent
  p_value <- ttest_result$p.value
  annotation <- ifelse(p_value < 0.001, '***', 
                       ifelse(p_value < 0.01, '**', 
                              ifelse(p_value < 0.05, '*', 'ns')))
  return(list(p_value = p_value, annotation = annotation))
  }
      
      
results <- COHORT_SUBSET %>%
  group_by(CELL_LINE, CL_NAME_ON_PLOT, Date) %>%
  do({
    data <- .
    fold_change_data <- data %>%
      summarise(fold_change = mean(MEASUREMENT[CONDITION == "STIM"]) / mean(MEASUREMENT[CONDITION == "UNSTIM"]))
    ttest_results <- perform_ttest(data)
    cbind(fold_change_data, ttest_results)
    }) %>%
  ungroup()


# Extract annotations for plotting
annotations        <- results$annotation
names(annotations) <- results$CELL_LINE

# Reorder
results$CELL_LINE = reorder(results$CELL_LINE, -results$fold_change)
      
# Plotting the fold changes
plot <- ggplot(results, aes(x = CELL_LINE, y = fold_change)) +
  geom_col(position = position_dodge(width = 0.8)) +
  geom_text(aes(label = annotations), 
            hjust = -0.8) +
  theme_cowplot() +
  theme(legend.position = "bottom") +
  labs(x = "", y = "fold change") +
  coord_flip() +
  facet_wrap(~Date, scales = "free", ncol = 1)

plot

kable(results)
CELL_LINE CL_NAME_ON_PLOT Date fold_change p_value annotation
10xTA CHARMS-10xTA 2024-01-31 1.3035461 0.0453052 *
10xTA CHARMS-10xTA 2024-02-08 0.9389624 0.7807443 ns
10xTA CHARMS-10xTA 2024-02-12 0.9267334 0.5687440 ns
12xTA CHARMS-12xTA 2024-01-31 1.3582090 0.3124752 ns
12xTA CHARMS-12xTA 2024-02-08 1.0277136 0.8208756 ns
12xTA CHARMS-12xTA 2024-02-12 1.2273796 0.1372283 ns
15xTA CHARMS-15xTA 2024-01-31 19.3474265 0.3442921 ns
15xTA CHARMS-15xTA 2024-02-08 1.4532374 0.1074075 ns
15xTA CHARMS-15xTA 2024-02-12 3.7373913 0.0396862 *
Amy_1 CHARMS-BASS1_66307 (38-139) 2024-01-31 0.7358491 0.0728274 ns
BASS1_66306 CHARMS-BASS1_66306 2024-01-31 0.6356340 0.1943928 ns
BASS1_66306 CHARMS-BASS1_66306 2024-02-08 1.1596958 0.3238109 ns
BASS1_66306 CHARMS-BASS1_66306 2024-02-12 1.0476190 0.8104278 ns
BASS1_66307 CHARMS-BASS1_66307 2024-01-31 0.1754986 0.3525277 ns
BASS1_66307 CHARMS-BASS1_66307 2024-02-08 1.2079772 0.2626263 ns
BASS1_66307 CHARMS-BASS1_66307 2024-02-12 0.9938821 0.9780824 ns
Cl204 tKO_EL4 2024-02-12 1.1836735 0.0822047 ns
Cl69 cl069 2024-02-12 31.3660050 0.0036777 **
EDLD_1 CHARMS-EDLD_1 2024-01-31 1.5000000 0.4027161 ns
EDLD_1 CHARMS-EDLD_1 2024-02-08 0.6000000 0.2229713 ns
EDLD_3 CHARMS-EDLD_3 2024-02-08 0.7684211 0.6511889 ns
EDLD_6 CHARMS-EDLD_6 2024-01-31 0.8515901 0.8351990 ns
EDLD_9 CHARMS-EDLD_9 2024-01-31 0.7539267 0.4267866 ns
cl069 cl069 2024-01-31 26.0987856 0.0002203 ***
cl069 cl069 2024-02-08 20.1394422 0.0015975 **
cl204 tKO_EL4 2024-01-31 0.0550568 0.3307383 ns
cl204 tKO_EL4 2024-02-08 1.0402299 0.8506508 ns